home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 November / EnigmA AMIGA RUN 02 (1995)(G.R. Edizioni)(IT)[!][issue 1995-11][Skylink CD].iso / earcd / unix / mp14tar.z / mp14tar / mpack / macnapp.c < prev    next >
C/C++ Source or Header  |  1994-06-01  |  39KB  |  1,485 lines

  1. /* macnapp.c -- macintosh nifty application library
  2.  *
  3.  * (C) Copyright 1990-1993 by Christopher J. Newman
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation, and that the name of Christopher J. Newman not be used in
  11.  * advertising or publicity pertaining to distribution of the software without
  12.  * specific, written prior permission.  Christopher J. Newman makes no
  13.  * representations about the suitability of this software for any purpose.  It
  14.  * is provided "as is" without express or implied warranty.
  15.  *
  16.  * CHRISTOPHER J. NEWMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  17.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  18.  * SHALL CHRISTOPHER J. NEWMAN BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  19.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  20.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  21.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
  22.  * OF THIS SOFTWARE.
  23.  *
  24.  * Author:    Christopher J. Newman
  25.  * Message:    This is a nifty program.
  26.  *
  27.  * BUGS:
  28.  *    - should check 32bit mode works.
  29.  */
  30.  
  31. #ifndef THINK_C
  32. #include <Resources.h>
  33. #include <Dialogs.h>
  34. #include <Desk.h>
  35. #include <SegLoad.h>
  36. #include <OSEvents.h>
  37. #include <DiskInit.h>
  38. #include <Traps.h>
  39. #include <ToolUtils.h>
  40. #endif
  41. #include <AppleEvents.h>
  42. #include "macnapp.h"
  43.  
  44. /* export globals */
  45. na_win **NAhead = (na_win**) NULL;        /* head of the window tree */
  46. na_win **NAtask = (na_win**) NULL;        /* head of the task list */
  47. na_win **NActask = (na_win**) NULL;        /* next task to be called */
  48. na_win *NAwin = (na_win*) NULL;            /* the current window */
  49. na_menup NAmenup = (na_menup) NULL;        /* application menu procedure */
  50. short NAnewitem = 0;                    /* the new item number */
  51. short NAcloseitem = 0;                    /* the close item number */
  52. short NAappleitems = 0;                    /* number of apple menu items */
  53. Boolean NAhasedit = false;                /* true if application supports edit menu */
  54. long NAdelay = 30;                        /* delay (1/60th of a second) between null events */
  55. SysEnvRec NAsysenv;                        /* set up by Initialize */
  56. Boolean NAinBack = false;                /* true when app is in the background */
  57. short NAlastmouse = NA_RELEASE;            /* the last mouse event type */
  58. long NAmousetime = 0;                    /* the time of the last mouse up */
  59. Point NAmousept;                        /* the point (local) of last mouse down */
  60.  
  61. THz NAappzone;                            /* the application heap zone */
  62. RgnHandle NAfullRgn;                    /* a region containing everything */
  63. RgnHandle NAnullRgn;                    /* a region containing nothing */
  64. Cursor NAibeam;                            /* the Ibeam cursor */
  65. long NAgestaltBits;                        /* flags for gestalt options */
  66.  
  67. /* private globals */
  68. static Point    mselpoint;                /* the menu selection point */
  69. static short    aestatus;                /* if set, close everything */
  70.  
  71. /* constants for DoDraw procedure */
  72. #define    DO_UPDATE        0x0
  73. #define DO_RESIZE        0x1
  74. #define DO_ACTIVATE        0x2
  75. #define DO_DEACTIVATE    0x4
  76.  
  77. /* private routines */
  78.  
  79. static na_win **GetWinH(WindowPtr);
  80. static void DoDraw(na_win*, short);
  81. static short DoActivate(WindowPtr, na_win*, Boolean, Point p);
  82. static short DoMenu(na_win*, BYTE);
  83. static void AdjustCursor(na_win*, Point, Boolean);
  84. static short aboutmouse(na_win*, Point, short, short);
  85.  
  86. /* get the handle to a window
  87.  */
  88. static na_win **GetWinH(window)
  89.     WindowPtr    window;
  90. {
  91.     na_win        **winh;
  92.     
  93.     /* make positively sure that we have a valid handle */
  94.     if (window != (WindowPtr) NULL && !NAisDAWindow(window)) {
  95. #ifdef DEBUG
  96.         if (PtrZone((Ptr) window) == NAappzone && MemError() == noErr) {
  97. #endif
  98.             if ((winh = (na_win **) GetWRefCon(window)) != (na_win**) NULL) {
  99. #ifdef DEBUG
  100.                 if (HandleZone((Handle) winh) == NAappzone && MemError() == noErr) {
  101.                     if ((*winh)->pwin == window) {
  102. #endif
  103.                         return (winh);
  104. #ifdef DEBUG
  105.                     } else {
  106.                         NAdebug("Corrupted window structure found.\015");
  107.                         NAdebug("handle: %lx, pwin: %lx, window: %lx\015",
  108.                             (long) winh, (long) (*winh)->pwin, (long) window);
  109.                         Debugger();
  110.                     }
  111.                 } else {
  112.                     NAdebug("Corrupted Handle Zone Found.\015");
  113.                     NAdebug("handle: %lx, error: %ld\015", (long) winh,
  114.                         (long) MemError());
  115.                     Debugger();
  116.                 }        
  117. #endif
  118.             }
  119. #ifdef DEBUG
  120.         } else {
  121.             NAdebug("Corrupted Window Pointer Found.\n");
  122.             NAdebug("Pointer: %lx, error: %ld\n", (long) window, (long) MemError());
  123.             Debugger();
  124.         }
  125. #endif
  126.     }
  127.     return ((na_win**) NULL);
  128. }
  129.  
  130. /* handle drawing controls & growbox for update/activate events
  131.  */
  132. #ifdef __STDC__
  133. static void DoDraw(na_win *winp, short how)
  134. #else
  135. static void DoDraw(winp, how)
  136.     na_win    *winp;
  137.     short    how;
  138. #endif
  139. {
  140.     WindowPtr    window = winp->pwin;
  141.     long        flags = winp->flags;
  142.  
  143.     /* hilite or draw controls as appropriate */
  144.     if (flags & NA_HASCONTROLS) {
  145.         if (how & (DO_ACTIVATE | DO_DEACTIVATE)) {
  146.             if (flags & NA_HILITECTRLS) {
  147.                 ControlHandle ctrl;
  148.     
  149.                 for (ctrl = ((WindowPeek) window)->controlList; ctrl;
  150.                         ctrl = (*ctrl)->nextControl) {
  151.                     HiliteControl(ctrl, (how & DO_ACTIVATE) ? 0 : 255);
  152.                 }
  153.             }
  154.         } else {
  155.             DrawControls(window);
  156.         }
  157.     }
  158.     
  159.     /* draw the grow box properly -- mask out scroll bar outlines */
  160.     if (flags & NA_GROWBOX) {
  161.         Rect                tmpRect;
  162.         RgnHandle    tmpRgn = window->clipRgn;
  163.  
  164.         tmpRect.left = (tmpRect.right = window->portRect.right) - 15;
  165.         tmpRect.top = (tmpRect.bottom = window->portRect.bottom) - 15;
  166.         RectRgn(window->clipRgn = NewRgn(), &tmpRect);
  167.         DrawGrowIcon(window);
  168.         DisposeRgn(window->clipRgn);
  169.         window->clipRgn = tmpRgn;
  170.     }
  171.     
  172.     /* draw the default button on a dialog */
  173.     if (flags & NA_DEFBUTTON) NAdefaultButton(window);
  174.     
  175.     /* calculate the un-cursor region if the window size changed */
  176.     if (how & DO_RESIZE) NAcalcCursor(winp);
  177. }
  178.  
  179. /* handle activate event (either activate or MultiFinder suspend/resume)
  180.  */
  181. #ifdef __STDC__
  182. static short DoActivate(WindowPtr window, na_win *winp, Boolean activate, Point p)
  183. #else
  184. static short DoActivate(window, winp, activate, p)
  185.     WindowPtr            window;
  186.     na_win        *winp;
  187.     Boolean    activate;
  188.     Point                p;
  189. #endif
  190. {
  191.     na_win **winh;
  192.     short    status = NA_NOTPROCESSED;
  193.  
  194.     /* unlock current front window */
  195.     if (winp != (na_win*) NULL) {
  196.         NAunlockWindow(winp);
  197.         NAwin = (na_win*) NULL;
  198.     }
  199.     
  200.     /* check if there is a new window, and lock it */
  201.     if (window == (WindowPtr) NULL)  return (NA_PROCESSED);
  202.     
  203.     /* for app windows, update the cursor, call the activate proc, and DoDraw */
  204.     if ((NAwin = winp = NAlockWindow(winh = GetWinH(window))) != (na_win*) NULL) {
  205.         GrafPtr            tmpPort;
  206.  
  207.         GetPort(&tmpPort);
  208.         SetPort(window);
  209.         if (winp->cursorRgn != (RgnHandle) NULL && ((activate && !NAinBack)
  210.                 || winp->flags & NA_CURSORON)) {
  211.             LocalToGlobal(&p);
  212.             AdjustCursor(winp, p, activate);
  213.         }
  214.         if (winp->activep == (na_activep) NULL
  215.                 || (status = (*winp->activep)(winp, activate)) == NA_NOTPROCESSED) {
  216.             DoDraw(winp, activate ? DO_ACTIVATE : DO_DEACTIVATE);
  217.         }
  218.         if (!activate || winp->pwin != FrontWindow()) {
  219.             SetPort(tmpPort);
  220.             NAunlockWindowh(winh, winp);
  221.             NAwin = (na_win*) NULL;
  222.         }
  223.     }
  224.     
  225.     return (status);
  226. }
  227.  
  228. /* handle menu selection -- either menu click or menu shortcut
  229.  */
  230. #ifdef __STDC__
  231. static short DoMenu(na_win *winp, BYTE key)
  232. #else
  233. static short DoMenu(winp, key)
  234.     na_win        *winp;
  235.     BYTE        key;
  236. #endif
  237. {
  238.     WindowPtr    window = FrontWindow();
  239.     short         status = NA_NOTPROCESSED;
  240.     WORD        menuid, itemno;
  241.     
  242.     /* enable/disable edit menu as appropriate */
  243.     if (NAhasedit) {
  244.         MenuHandle    mnu = GetMHandle(mEdit);
  245.         
  246.         if (NAisDAWindow(window)) {
  247.             EnableItem(mnu, iUndo);
  248.             for (itemno = iCut; itemno <= iClear; itemno++) {
  249.                 EnableItem(mnu, itemno);
  250.             }
  251.         } else {
  252.             DisableItem(mnu, iUndo);
  253.             for (itemno = iCut; itemno <= iClear; itemno++) {
  254.                 DisableItem(mnu, itemno);
  255.             }
  256.         }
  257.     }
  258.     
  259.     /* enable/disable the close menu as appropriate */
  260.     if (NAcloseitem) {
  261.         MenuHandle    mnu = GetMHandle(mFile);
  262.         
  263.         if (window != (WindowPtr) NULL && (winp == (na_win*) NULL
  264.                 || winp->pwin != window || winp->flags & NA_CLOSEBOX)) {
  265.             EnableItem(mnu, NAcloseitem);
  266.         } else {
  267.             DisableItem(mnu, NAcloseitem);
  268.         }
  269.     }
  270.     
  271.     /* call menu proc to enable/disable items as appropriate */
  272.     if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
  273.         status = (*winp->menup)(winp, (WORD) 0, (WORD) key);
  274.     }
  275.     if (status == NA_NOTPROCESSED && NAmenup != (na_menup) NULL) {
  276.         status = (*NAmenup)(winp, (WORD) 0, (WORD) key);
  277.     }
  278.     if (status != NA_NOTPROCESSED) return (status);
  279.     
  280.     /* get menu selection */
  281.     {
  282.         long    menusel = (key == 0) ? MenuSelect(mselpoint) : MenuKey(key);
  283.  
  284.         itemno = LOWORD(menusel);
  285.         if ((menuid = HIWORD(menusel)) == 0) menuid = 1;
  286.     }
  287.     
  288.     /* check for DA menu items */
  289.     switch (menuid) {
  290.         case mApple:    /* check for a desk accessary selection */
  291.             if (itemno > NAappleitems) {
  292.                 PCstr            mItem[256];
  293.             
  294.                 GetItem(GetMHandle(menuid), itemno, mItem);
  295.                 OpenDeskAcc(mItem);
  296.                 menuid = 1;
  297.             }
  298.             break;
  299.         
  300.         case mFile:        /* check for the close menu item for DAs */
  301.             if (itemno == NAcloseitem && NAisDAWindow(window)) {
  302.                 CloseDeskAcc(((WindowPeek) window)->windowKind);
  303.                 menuid = 1;
  304.             }
  305.             break;
  306.     
  307.         case mEdit:     /* check for the edit menu for DAs */
  308.             if (NAhasedit && itemno <= iClear && SystemEdit(itemno - iUndo)) {
  309.                 menuid = 1;
  310.             }
  311.             break;
  312.     }
  313.     
  314.     /* call menu proc to handle/disable items */
  315.     if (winp != (na_win*) NULL && winp->menup != (na_menup) NULL) {
  316.         status = (*winp->menup)(winp, menuid, itemno);
  317.     }
  318.     if (status != NA_PROCESSED && NAmenup != (na_menup) NULL) {
  319.         status = (*NAmenup)(winp, menuid, itemno);
  320.     }
  321.     
  322.     /* if close item wasn't processed, process it */
  323.     if (status == NA_NOTPROCESSED && menuid == mFile && itemno == NAcloseitem) {
  324.         status = NA_REQCLOSE;
  325.     }
  326.     
  327.     /* turn off the menu */
  328.     HiliteMenu(0);
  329.     
  330.     return (status);
  331. }
  332.  
  333. /* set the cursor icon appropriately
  334.  */
  335. #ifdef __STDC__
  336. static void AdjustCursor(na_win *winp, Point gmouse, Boolean active)
  337. #else
  338. static void AdjustCursor(winp, gmouse, active)
  339.     na_win    *winp;
  340.     Point            gmouse;
  341.     Boolean            active;
  342. #endif
  343. {
  344.     short    status = NA_NOTPROCESSED;
  345.     
  346.     /* don't change the cursor when in wrong window */
  347.     if (active && FrontWindow() != winp->pwin) return;
  348.     
  349.     /* if the cursor is on */
  350.     if (winp->flags & NA_CURSORON) {
  351.         /* and the point moves outside the cursor region or window is deactivated
  352.          * turn cursor off */
  353.         if (!active || PtInRgn(gmouse, winp->uncrsrRgn)) {
  354.             winp->flags &= ~NA_CURSORON;
  355.             if (winp->cursorp == (na_cursorp*) NULL) {
  356.                 SetCursor(&QD(arrow));
  357.             } else {
  358.                 goto DOCURSORP;
  359.             }
  360.         }
  361.     
  362.     /* if the cursor is off and the point moves into the window, turn cursor on */
  363.     } else if (PtInRgn(gmouse, winp->cursorRgn)) {
  364.         winp->flags |= NA_CURSORON;
  365.         if (winp->cursorp == (na_cursorp) NULL) {
  366.             SetCursor(&NAibeam);
  367.         } else {
  368.         DOCURSORP:
  369.             GlobalToLocal(&gmouse);
  370.             status = (*winp->cursorp)(winp, gmouse);
  371.         }
  372.     }
  373.     
  374.     /* if cursor event was processed, reset the un-cursor region */
  375.     if (status == NA_PROCESSED) NAcalcCursor(winp);
  376. }
  377.  
  378.  
  379. /* export routines */
  380.  
  381. /* save the current window position in a resource file
  382.  */
  383. void NAsaveWin(winp)
  384.     na_win    *winp;
  385. {
  386.     Rect        *rptr;
  387.     WindowPtr    window = winp->pwin;
  388.     Handle        wind = GetResource('WIND', winp->resid);
  389.     
  390.     HLock(wind);
  391.     rptr = (Rect *) *wind;
  392.     rptr->right = (rptr->left = -window->portBits.bounds.left)
  393.         + window->portRect.right;
  394.     rptr->bottom = (rptr->top = -window->portBits.bounds.top)
  395.         + window->portRect.bottom;
  396.     ChangedResource(wind);
  397.     HUnlock(wind);
  398. }
  399.  
  400. /* calculate the cursor regions for Multi-Finder
  401.  */
  402. void NAcalcCursor(winp)
  403.     na_win    *winp;
  404. {
  405.     if (winp->cursorRgn != (RgnHandle) NULL) {
  406.         if (winp->uncrsrRgn == (RgnHandle) NULL)  winp->uncrsrRgn = NewRgn();
  407.         DiffRgn(NAfullRgn, winp->cursorRgn, winp->uncrsrRgn);
  408.     }
  409. }
  410.  
  411. /* lock a window context
  412.  */
  413. na_win *NAlockWindow(winh)
  414.     na_win **winh;
  415. {
  416.     if (winh == (na_win**) NULL) return ((na_win*) NULL);
  417.     if (!(*winh)->locks++) {
  418.         MoveHHi((Handle) winh);
  419.         HLock((Handle) winh);
  420.     }
  421.     
  422.     return (*winh);
  423. }
  424.  
  425. /* request or force a window to close
  426.  */
  427. #ifdef __STDC__
  428. short NAcloseWindow(na_win *winp, short status)
  429. #else
  430. short NAcloseWindow(winp, status)
  431.     na_win    *winp;
  432.     short    status;
  433. #endif
  434. {
  435.     na_win    **winh, ***whp;
  436.     short childstatus;
  437.     na_closep closeproc = (na_closep) NULL;
  438.     
  439.     if (winp == (na_win*) NULL) return (NA_NOTPROCESSED);
  440.     switch (status) {
  441.         case NA_REQCLOSE:
  442.             /* check if window ready to close */
  443.             status = NA_CLOSED;
  444.             if ((closeproc = winp->closep) != (na_closep) NULL) {
  445.                 status = (*closeproc)(winp);
  446.                 closeproc = winp->closep == closeproc ? (na_closep) NULL : closeproc;
  447.             }
  448.             if (status > NA_CLOSED)        break;
  449.         case NA_CLOSED:
  450.             /* close children */
  451.             childstatus = NAcloseWindows(winp->child, NA_REQCLOSEALL);
  452.             /* clear current window */
  453.             if (winp == NAwin) NAwin = (na_win*) NULL;
  454.             /* reset the cursor */
  455.             if (winp->flags & NA_CURSORON) SetCursor(&QD(arrow));
  456.             /* dispose of any cursor regions */
  457.             if (winp->cursorRgn != (RgnHandle) NULL) DisposeRgn(winp->cursorRgn);
  458.             if (winp->uncrsrRgn != (RgnHandle) NULL) DisposeRgn(winp->uncrsrRgn);
  459.             /* close the window */
  460.             if (winp->pwin != (WindowPtr) NULL) {
  461.                 if (winp->flags & NA_DIALOGWINDOW) {
  462.                     DisposDialog((DialogPtr) winp->pwin);
  463.                 } else {
  464.                     DisposeWindow(winp->pwin);
  465.                 }
  466.             }
  467.             /* remove from window list */
  468.             winh = (na_win**) RecoverHandle((Ptr) winp);
  469. #ifdef DEBUG
  470.             if (MemError() != noErr || *winh != winp) {
  471.                 NAdebug("Handle error: pointer: %x, handle: %x, error: %d, zone: %x\015",
  472.                     (long) winp, (long) winh, (long) MemError(),
  473.                     (long) GetZone());
  474.                 Debugger();
  475.             }
  476. #endif /* DEBUG */
  477.             whp = &NAhead;
  478.             if (winp->parent != (na_win**) NULL) whp = &(*winp->parent)->child;
  479.             while (*whp != (na_win**) NULL) {
  480.                 if (*whp == winh) {
  481.                     *whp = winp->next;
  482.                 } else {
  483.                     whp = &(**whp)->next;
  484.                 }
  485.             }
  486.             /* relink children in list */
  487.             if (childstatus > NA_ALLCLOSED) {
  488.                 *whp = winp->child;
  489.                 do {
  490.                     (**whp)->parent = winp->parent;
  491.                     whp = &(**whp)->next;
  492.                 } while (*whp != (na_win**) NULL);
  493.                 *whp = winp->next;
  494.             }
  495.             /* remove from task list */
  496.             whp = &NAtask;
  497.             while (*whp != (na_win**) NULL && *whp != winh) {
  498.                 whp = &(**whp)->task;
  499.             }
  500.             *whp = winp->task;
  501.             NActask = (na_win**) NULL;
  502.             /* after-close function */
  503.             if (closeproc != (na_closep) NULL) (*closeproc)(winp);
  504.             /* destroy window structure */
  505.             DisposHandle((Handle) winh);
  506.             if (status < NA_CLOSED) {
  507.                 if ((status = NAcloseWindows(NAhead, status)) > NA_CLOSED) {
  508.                     status = NA_CLOSED;
  509.                 }
  510.             }
  511.             break;
  512.     }
  513.     
  514.     return (status);            
  515. }
  516.  
  517. #ifdef __STDC__
  518. short NAcloseWindows(na_win **winh, short status)
  519. #else
  520. short NAcloseWindows(winh, status)
  521.     na_win    **winh;
  522.     short            status;
  523. #endif
  524. {
  525.     na_win    *winp, **lasth;
  526.     short    substatus;
  527.     
  528.     while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
  529.         lasth = winh;
  530.         winh = winp->next;
  531.         substatus = NAcloseWindow(winp, status + 2);
  532.         if (substatus > NA_CLOSED) {
  533.             NAunlockWindowh(lasth, winp);
  534.             return (NA_NOTPROCESSED);
  535.         }
  536.         if (substatus < NA_CLOSED) return (substatus);
  537.     }
  538.     
  539.     return (NA_ALLCLOSED);
  540. }
  541.  
  542. /* remove the window on a mouse-up event
  543.  */
  544. #ifdef __STDC__
  545. static short aboutmouse(na_win *winp, Point mousep, short type, short mods)
  546. #else
  547. static short aboutmouse(winp, mousep, type, mods)
  548.     na_win    *winp;
  549.     Point    mousep;
  550.     short    type, mods;
  551. #endif
  552. #ifdef applec
  553. #pragma unused (winp, mousep, mods)
  554. #endif
  555. {
  556.     return (type & 1 ? NA_REQCLOSE : NA_PROCESSED);
  557. }
  558.  
  559. /* a standard about box init procedure
  560.  */
  561. short NAabout(winp, dptr)
  562.     na_win    *winp;
  563.     long    *dptr;
  564. #ifdef applec
  565. #pragma unused (dptr)
  566. #endif
  567. {
  568.     short    item;
  569.     
  570.     ShowWindow(winp->pwin);
  571.     winp->mousep = aboutmouse;
  572.     
  573.     return (NA_PROCESSED);
  574. }
  575.  
  576. /* flash a button in a dialog box for equivalent keypresses
  577.  */
  578. #ifdef __STDC__
  579. void NAflashButton(DialogPtr dialog, short item)
  580. #else
  581. void NAflashButton(dialog, item)
  582.     DialogPtr    dialog;
  583.     short        item;
  584. #endif
  585. {
  586.     long    scratch;
  587.     short    type;
  588.     Handle    ctrl;
  589.     Rect    box;
  590.     
  591.     GetDItem(dialog, item, &type, &ctrl, &box);
  592.     if (type == ctrlItem + btnCtrl) {
  593.         HiliteControl((ControlHandle) ctrl, 1);
  594.         Delay(5, &scratch);
  595.         HiliteControl((ControlHandle) ctrl, 0);
  596.     }
  597. }
  598.  
  599. /* draw the default button
  600.  */
  601. void NAdefaultButton(dialog)
  602.     DialogPtr    dialog;
  603. {
  604.     Rect    tmpRect;
  605.     
  606.     NAgetDRect(dialog, iOk, &tmpRect);
  607.     {
  608.         PenState        pnState;
  609.         
  610.         GetPenState(&pnState);
  611.         PenNormal();
  612.         PenSize(3, 3);
  613.         InsetRect(&tmpRect, -4, -4);
  614.         FrameRoundRect(&tmpRect, 16, 16);
  615.         SetPenState(&pnState);
  616.     }
  617. }
  618.  
  619. /* send an event message to all windows
  620.  */
  621. short NAallWindows(winh, pevent)
  622.     na_win    **winh;
  623.     EventRecord        *pevent;
  624. {
  625.     na_win *winp, **oldwinh;
  626.     short    status = NA_NOTPROCESSED;
  627.     
  628.     while ((winp = NAlockWindow(winh)) != (na_win*) NULL) {
  629.         oldwinh = winh;
  630.         winh = winp->next;
  631.         if (winp->miscp != (na_miscp) NULL) {
  632.             GrafPtr    tempPort;
  633.             
  634.             GetPort(&tempPort);
  635.             SetPort(winp->pwin);
  636.             status = (*winp->miscp)(winp, pevent);
  637.             SetPort(tempPort);
  638.         }
  639.         if ((status == NA_CLOSED || status == NA_REQCLOSE)
  640.                 && NAcloseWindow(winp, status) == NA_CLOSED) {
  641.             continue;
  642.         }
  643.         NAunlockWindowh(oldwinh, winp);
  644.         if (status == NA_ALLCLOSED || status == NA_REQCLOSEALL) {
  645.             if (NAcloseWindows(NAhead, status) == NA_ALLCLOSED) {
  646.                 return (NA_ALLCLOSED);
  647.             }
  648.             /* make sure our handle is still valid */
  649.             if (GetHandleSize((Handle) oldwinh) == 0) continue;
  650.         }
  651.         if ((*oldwinh)->child != (na_win**) NULL &&
  652.                 NAallWindows((*oldwinh)->child, pevent) == NA_ALLCLOSED) {
  653.             return (NA_ALLCLOSED);
  654.         }
  655.     }
  656.     
  657.     return (NA_PROCESSED);
  658. }
  659.  
  660. /* apple event handler
  661.  */
  662. pascal OSErr NArequiredAE(AppleEvent *, AppleEvent *, long);
  663. pascal OSErr NArequiredAE(event, reply, ref)
  664.     AppleEvent *event, *reply;
  665.     long ref;
  666. {
  667.     na_openp openp = (na_openp) ref;
  668.     OSErr err;
  669.     DescType actualType, eventID;
  670.     Size actualSize;
  671.     AEDescList doclist;
  672.     long count, i;
  673.     short gotdoc;
  674.     FSSpec fspec;
  675.     AEKeyword keywd;
  676.     
  677.     err = AEGetAttributePtr(event, keyEventIDAttr, typeType, &actualType,
  678.         (Ptr) &eventID, sizeof (eventID), &actualSize);
  679.     if (err == noErr) {
  680.         gotdoc = 0;
  681.         if (eventID == kAEOpenDocuments || eventID == kAEPrintDocuments) {
  682.             err = AEGetParamDesc(event, keyDirectObject, typeAEList, &doclist);
  683.             if (err == noErr) gotdoc = 1;
  684.         }
  685.         if (err == noErr) {
  686.             err = AEGetAttributePtr(event, keyMissedKeywordAttr, typeWildCard,
  687.                 &actualType, NULL, 0, &actualSize);
  688.             if (err == errAEDescNotFound) {
  689.                 err = noErr;
  690.             } else if (err == noErr) {
  691.                 err = errAEEventNotHandled;
  692.             }
  693.         }
  694.         if (err == noErr) switch (eventID) {
  695.             case kAEOpenApplication:
  696.                 if (NAmenup && NAnewitem) {
  697.                     aestatus = (*NAmenup)(NULL, mFile, NAnewitem);
  698.                 }
  699.                 break;
  700.             case kAEOpenDocuments:
  701.             case kAEPrintDocuments:
  702.                 err = AECountItems(&doclist, &count);
  703.                 if (err != noErr) break;
  704.                 for (i = 1; i <= count; ++i) {
  705.                     err = AEGetNthPtr(&doclist, i, typeFSS, &keywd, &actualType,
  706.                         (Ptr) &fspec, sizeof (fspec), &actualSize);
  707.                     if (err != noErr) break;
  708.                     if (!openp || (*openp)(eventID == kAEOpenDocuments
  709.                                 ? appOpen : appPrint, 0, &fspec) < 0) {
  710.                         err = errAEEventNotHandled;
  711.                         break;
  712.                     }
  713.                 }
  714.                 break;
  715.             case kAEQuitApplication:
  716.                 aestatus = NA_ALLCLOSED;
  717.                 if (NAhead != NULL) {
  718.                     aestatus = NAcloseWindows(NAhead, NA_REQCLOSEALL);
  719.                     if (aestatus != NA_ALLCLOSED) err = userCanceledErr;
  720.                 }
  721.                 break;
  722.         }
  723.         if (gotdoc) {
  724.             AEDisposeDesc(&doclist);
  725.         }
  726.     }
  727.     
  728.     return (err);
  729. }
  730.  
  731. /* call the main loop procedure
  732.  */
  733. void NAmainloop()
  734. {
  735.     na_win        *winp;
  736.     Boolean    gotEvent;
  737.     Boolean    dialogAction;
  738.     EventRecord            event;
  739.     Point                mouse;
  740.     short        status;
  741.     short                itemHit;
  742.     DialogPtr            dialog;
  743.     
  744.     UnloadSeg((Ptr) NAinit);        /* unload the initialize routine */
  745.     
  746.     MAINLOOP:
  747.     /* check for a window in front */
  748.     {
  749.         WindowPtr    window;
  750.         
  751.         if ((winp = NAwin) == (na_win*) NULL
  752.                 && (window = FrontWindow()) != (WindowPtr) NULL
  753.                 && (NAwin = winp = NAlockWindow(GetWinH(window))) != (na_win *) NULL) {
  754.             SetPort(window);
  755.         }
  756.     }
  757.  
  758.     /* get an event */
  759.     {
  760.         RgnHandle    rgn = NAfullRgn;
  761.         short        delay = NAdelay;
  762.         
  763.         /* if there is an app window in front, use app delay & cursor region */
  764.         if (winp != (na_win*) NULL) {
  765.             delay = winp->delay;
  766.             if (winp->cursorRgn != (RgnHandle) NULL && !NAinBack) {
  767.                 rgn = winp->cursorRgn;
  768.                 if (!(winp->flags & NA_CURSORON)) rgn = winp->uncrsrRgn;
  769.             }
  770.             if (winp->mousepix && !(NAlastmouse & 1)) {
  771.                 rgn = NAnullRgn;
  772.                 delay = 0;
  773.             }
  774.         }
  775.         gotEvent = WaitNextEvent(everyEvent, &event, delay, rgn);
  776.     }
  777.     status = NA_NOTPROCESSED;
  778.     
  779.     /* get mouse position */
  780.     mouse = event.where;
  781.     GlobalToLocal(&mouse);
  782.     
  783.     /* check for dialog events */
  784.     dialogAction = FrontWindow() != (WindowPtr) NULL ? IsDialogEvent(&event) : false;
  785.     if (dialogAction && event.what != keyDown && event.what != autoKey
  786.             && event.what != updateEvt) {
  787.         ControlHandle    ctrl;
  788.         
  789.         if (DialogSelect(&event, &dialog, &itemHit) && winp != (na_win*) NULL) {
  790.     DOCONTROLP:
  791.             if (winp->ctrlp != (na_ctrlp) NULL) {
  792.                 NAgetDHandle(dialog, itemHit, &ctrl);
  793.                 status = (*winp->ctrlp)(winp, mouse, itemHit, event.modifiers, ctrl);
  794.                 gotEvent = false;
  795.             }
  796.         }
  797.     }
  798.                 
  799.     /* handle the event */
  800.     if (gotEvent) switch (event.what) {
  801.         case mouseUp:
  802.             /* deal with mouse up events to keep track of double/triple clicks */
  803.             if (NAlastmouse & 1) break;
  804.             ++NAlastmouse;
  805.             NAmousetime = TickCount();
  806.             if (winp == (na_win*) NULL) break;
  807.         DOMOUSEP:
  808.             if (winp->mousep != (na_mousep) NULL) {
  809.                 status = (*winp->mousep)(winp, mouse, NAlastmouse, event.modifiers);
  810.             }
  811.             break;
  812.  
  813.         case mouseDown:
  814.             if (winp != (na_win*) NULL && winp->flags & NA_MODAL
  815.                     && !PtInRect(mouse, &winp->pwin->portRect)) {
  816.                 SysBeep(10);
  817.                 break;
  818.             }
  819.             {
  820.                 short    part;
  821.                 WindowPtr        window;
  822.                 
  823.                 /* deal with mouse down events */
  824.                 switch (part = FindWindow(event.where, &window)) {
  825.                     case inMenuBar:
  826.                         /* call an appropriate menu bar handler */
  827.                         mselpoint = event.where;
  828.                         status = DoMenu(winp, 0);
  829.                         break;
  830.                         
  831.                     case inSysWindow:
  832.                         /* System Click in DA */
  833.                         SystemClick(&event, window);
  834.                         break;
  835.     
  836.                     case inContent:
  837.                         /* click a window to front if not in front */
  838.                         if (window != FrontWindow()) {
  839.                             SelectWindow(window);
  840.                             if (winp != (na_win*) NULL) NAunlockWindow(winp);
  841.                             NAwin = (na_win*) NULL;
  842.                             NAlastmouse = NA_RELEASE;
  843.                             break;
  844.                         }
  845.                         
  846.                         /* don't bother processing further if no mouse proc */
  847.                         if (winp == (na_win*) NULL) break;
  848.     
  849.                         /* check for control events */
  850.                         if (winp->ctrlp != (na_ctrlp) NULL && winp->flags & NA_HASCONTROLS) {
  851.                             ControlHandle    hctl;
  852.                             short    item;
  853.                             
  854.                             if ((item = FindControl(mouse, window, &hctl)) != 0
  855.                                     && (status = (*winp->ctrlp)(winp, mouse, item,
  856.                                     event.modifiers, hctl)) != NA_NOTPROCESSED) {
  857.                                 break;
  858.                             }
  859.                         }
  860.                         
  861.                         /* deal with double clicks */
  862.                         if ((NAlastmouse & 1) && NAlastmouse < NA_RELEASE
  863.                                 && event.when - NAmousetime <= GetDblTime()) {
  864.                             if (++NAlastmouse > NA_DOWNN) NAlastmouse = NA_DOWNN;
  865.                         } else {
  866.                             NAlastmouse = NA_DOWN1;
  867.                         }
  868.                         NAmousept = mouse;
  869.                         
  870.                         /* call the mouse handler */
  871.                         goto DOMOUSEP;
  872.     
  873.                     case inDrag:
  874.                         /* drag the window */
  875.                         {
  876.                             Rect             tmpRect, bRect;
  877.                             na_win    **wh, *wp;
  878.                             
  879.                             {
  880.                                 int        four = 4;
  881.                                 
  882.                                 tmpRect = QD(screenBits.bounds);
  883.                                 InsetRect(&tmpRect, four, four);
  884.                             }
  885.                             bRect = window->portBits.bounds;
  886.                             DragWindow(window, event.where, &tmpRect);
  887.                             if ((bRect.left != window->portBits.bounds.left
  888.                                     || bRect.top != window->portBits.bounds.top) &&
  889.                                     (wp = NAlockWindow(wh = GetWinH(window))) != NULL) {
  890.                                 if (wp->flags & NA_SMARTSIZE) NAsaveWin(wp);
  891.                                 if (wp->cursorRgn != (RgnHandle) NULL) {
  892.                                     OffsetRgn(wp->cursorRgn,
  893.                                         bRect.left - window->portBits.bounds.left,
  894.                                         bRect.top - window->portBits.bounds.top);
  895.                                     NAcalcCursor(wp);
  896.                                 }
  897.                                 NAunlockWindowh(wh, wp);
  898.                             }
  899.                         }
  900.                         break;
  901.                     
  902.                     case inGoAway:
  903.                         /* deal with the close window box */
  904.                         if (TrackGoAway(window, event.where)) status = NA_REQCLOSE;
  905.                         break;
  906.     
  907.                     case inGrow:
  908.                         /* grow the window */
  909.                         {
  910.                             Rect            tmpRect;
  911.                             long    growInfo;
  912.                             
  913.                             /* assume there is a valid app window in front */
  914.                             /* calculate min & max grow dimensions */
  915.                             tmpRect = QD(screenBits.bounds);
  916.                             tmpRect.bottom -= tmpRect.top;
  917.                             tmpRect.right -= tmpRect.left;
  918.                             tmpRect.top = winp->minh;
  919.                             tmpRect.left = winp->minw;
  920.                             if (winp->maxh) tmpRect.bottom = winp->maxh;
  921.                             if (winp->maxw) tmpRect.right = winp->maxw;
  922.                             
  923.                             /* check for resize proc */
  924.                             if (winp->resizep != (na_resizep) NULL) {
  925.                                 status = (*winp->resizep)(winp, event.where, &tmpRect);
  926.                                 if (status == NA_PROCESSED) break;
  927.                                 goto RESIZEWINDOW;
  928.                             }
  929.                             
  930.                             /* grow, resize, and update the window */
  931.                             if ((growInfo = GrowWindow(window, event.where, &tmpRect))) {
  932.                                 SizeWindow(window, LOWORD(growInfo), HIWORD(growInfo),
  933.                                     false);
  934.                                 goto RESIZEWINDOW;
  935.                             }
  936.                         }
  937.                         break;
  938.                     
  939.                     case inZoomIn:
  940.                     case inZoomOut:
  941.                         /* assume there is a valid app window in front */
  942.                         /* track, zoom, and update the window */
  943.                         if (TrackBox(window, event.where, part)) {
  944.                             SetPort(window);
  945.                             EraseRect(&window->portRect);
  946.                             ZoomWindow(window, part, true);
  947.                     RESIZEWINDOW:
  948.                             if (winp != (na_win*) NULL) {
  949.                                 if (winp->flags & NA_SMARTSIZE) NAsaveWin(winp);
  950.                                 if (winp->updatep == (na_updatep) NULL ||
  951.                                         (status = (*winp->updatep)(winp, (Boolean) true))
  952.                                         == NA_NOTPROCESSED) {
  953.                                     DoDraw(winp, DO_RESIZE);
  954.                                 }
  955.                             }
  956.                             ValidRect(&window->portRect);
  957.                         }
  958.                         break;
  959.                 }
  960.             }
  961.             break;
  962.         
  963.         case keyDown:
  964.         case autoKey:
  965.             /* deal with keyboard events */
  966.             {
  967.                 long    key = event.message & charCodeMask;
  968.  
  969.                 /* translate command-foo to an appropriate menu operation */
  970.                 if (!(winp->flags & NA_MODAL)) {
  971.                     if ((event.modifiers & cmdKey) && event.what == keyDown &&
  972.                             (status = DoMenu(winp, key)) != NA_NOTPROCESSED) {
  973.                         break;
  974.                     }
  975.                 }
  976.                 
  977.                 /* require an app window for further processing */
  978.                 if (winp == (na_win*) NULL) break;
  979.  
  980.                 /* call the window's key handling procedure */
  981.                 if (winp->keyp != (na_keyp) NULL) {
  982.                     status = (*winp->keyp)(winp, winp->flags & NA_RAWKEY ? event.message : key,
  983.                         event.modifiers);
  984.                 }
  985.                 
  986.                 /* if it's an unprocessed event in a dialog window */
  987.                 if ((status == NA_NOTPROCESSED || status == NA_DPROCESSED)
  988.                     && (winp->flags & NA_DIALOGWINDOW)) {
  989.                     ControlHandle    ctrl;
  990.                     
  991.                     /* check for return/ESC/command-. */
  992.                     itemHit = 0;
  993.                     if (status == NA_NOTPROCESSED) switch (key) {
  994.                         case '\r':
  995.                         case '\n':
  996.                             NAgetDHandle((DialogPtr)winp->pwin, iOk, &ctrl);
  997.                             if (ctrl && !(*ctrl)->contrlHilite) {
  998.                                 itemHit = iOk;
  999.                             }
  1000.                             break;
  1001.                         
  1002.                         case '.':
  1003.                             if (!(event.modifiers & cmdKey)) break;
  1004.                         case '\033':
  1005.                             itemHit = iCancel;
  1006.                             break;
  1007.                     }
  1008.                     
  1009.                     /* if it's a special key, flash it's item */
  1010.                     dialog = winp->pwin;
  1011.                     if (itemHit) {
  1012.                         NAflashButton(dialog, itemHit);
  1013.                     } else if ((event.modifiers & cmdKey)
  1014.                             || !DialogSelect(&event, &dialog, &itemHit)) {
  1015.                         break;
  1016.                     }
  1017.                     
  1018.                     /* if there's a control procedure, call it, otherwise ignore */
  1019.                     if (winp->ctrlp != (na_ctrlp) NULL) goto DOCONTROLP;
  1020.                 }
  1021.             }
  1022.             break;
  1023.         
  1024.         case activateEvt:
  1025.             /* deal with activate windows based on activeFlag */
  1026.             status = DoActivate((WindowPtr) event.message, winp,
  1027.                 event.modifiers & activeFlag, mouse);
  1028.             break;
  1029.             
  1030.         case updateEvt:
  1031.             /* deal with update events with proper port setting, etc. */
  1032.             {
  1033.                 na_win        *wp;
  1034.                 WindowPtr    window;
  1035.                 na_win                 **winh;
  1036.                 GrafPtr                tempPort;
  1037.                 
  1038.                 window = (WindowPtr) event.message;
  1039.                 BeginUpdate(window);
  1040.                 if ((wp = NAlockWindow(winh = GetWinH(window))) != (na_win*) NULL) {
  1041.                     GetPort(&tempPort);
  1042.                     SetPort(window);
  1043.                     if (wp->flags & NA_DIALOGUPDATE) {
  1044.                         UpdtDialog(window, window->visRgn);
  1045.                         status = NA_PROCESSED;
  1046.                     }
  1047.                     if (wp->updatep == (na_updatep) NULL
  1048.                             || (status = (*wp->updatep)(wp, (Boolean) false))
  1049.                             == NA_NOTPROCESSED) {
  1050.                         DoDraw(wp, DO_UPDATE);
  1051.                     }
  1052.                     if (status == NA_NOTPROCESSED && dialogAction) {
  1053.                         (void) DialogSelect(&event, &dialog, &itemHit);
  1054.                     }
  1055.                     SetPort(tempPort);
  1056.                     NAunlockWindowh(winh, wp);
  1057.                 }
  1058.                 EndUpdate(window);
  1059.             }
  1060.             break;
  1061.         
  1062.         case diskEvt:
  1063.             /* let the user format bad disks */
  1064.             if (HIWORD(event.message) != noErr) {
  1065.                 Point    ptemp;
  1066.                 
  1067.                 SetPt(&ptemp, 0x0070, 0x0050);
  1068.                 (void) DIBadMount(ptemp, event.message);
  1069.             } else {
  1070.                 status = NAallWindows(NAhead, &event);
  1071.             }
  1072.             break;
  1073.         
  1074.         case networkEvt:
  1075.         case driverEvt:
  1076.         case app1Evt:
  1077.         case app2Evt:
  1078.         case app3Evt:
  1079.             /* send event to all windows */
  1080.             status = NAallWindows(NAhead, &event);
  1081.             break;
  1082.         
  1083.         case osEvt:
  1084.             switch ((event.message >> 24) & 0xff) {
  1085.                 case suspendResumeMessage:
  1086.                     status = DoActivate(FrontWindow(), winp,
  1087.                         !(NAinBack = !(event.message & resumeFlag)), mouse);
  1088.                     break;
  1089.                 
  1090.                 case mouseMovedMessage:
  1091.                     /* only interesting if a window is in front */
  1092.                     if (NAinBack || winp == (na_win*) NULL) break;
  1093.                     
  1094.                     {
  1095.                         short mousepix = winp->mousepix;
  1096.                         
  1097.                         /* deal with mouse dragging */
  1098.                         if (mousepix && !(NAlastmouse & 1)) {
  1099.                             if (NAlastmouse != NA_DRAG) {
  1100.                                 Rect    tmpRect;
  1101.                                 
  1102.                                 InsetRect(&tmpRect, -mousepix, -mousepix);
  1103.                                 if (PtInRect(mouse, &tmpRect)) break;
  1104.                                 NAlastmouse = NA_DRAG;
  1105.                             }
  1106.                             goto DOMOUSEP;
  1107.                         
  1108.                         /* deal with cursor moving in/out of window */
  1109.                         } else if (winp->cursorRgn != (RgnHandle) NULL) {
  1110.                             AdjustCursor(winp, event.where, true);
  1111.                         }
  1112.                     }
  1113.                     break;
  1114.                 }
  1115.             break;
  1116.         
  1117.         case kHighLevelEvent:
  1118.             if (NAgestaltBits & NA_HASAEVENTS) {
  1119.                 aestatus = status;
  1120.                 (void) AEProcessAppleEvent(&event);
  1121.                 status = aestatus;
  1122.             }
  1123.             break;
  1124.     }
  1125.     
  1126.     /* call the idle procedure of the front window */
  1127.     if ((winp = NAwin) != (na_win*) NULL && !NAinBack
  1128.             && status >= NA_NOTPROCESSED && winp->idlep != (na_idlep) NULL) {
  1129.         status = (*winp->idlep)(winp);
  1130.     }
  1131.     
  1132.     /* deal with window/app close requests and events */
  1133.     switch (status) {
  1134.         case NA_ALLCLOSED:
  1135.         case NA_REQCLOSEALL:
  1136.             status = NAcloseWindows(NAhead, status);
  1137.             break;
  1138.             
  1139.         case NA_CLOSED:
  1140.         case NA_REQCLOSE:
  1141.             status = NAcloseWindow(winp, status);
  1142.             break;
  1143.         
  1144.         default:
  1145.             /* call the next task procedure */
  1146.             if (NAtask != (na_win**) NULL) {
  1147.                 static BYTE        prioritycnt;
  1148.                 na_win *wp;
  1149.                 GrafPtr            tempPort;
  1150.                 
  1151.                 if (NActask == (na_win**) NULL) {
  1152.                     NActask = NAtask;
  1153.                     prioritycnt = (*NAtask)->priority;
  1154.                 }
  1155.                 if ((wp = NAlockWindow(NActask)) != (na_win*) NULL
  1156.                         && wp->taskp != (na_taskp) NULL) {
  1157.                     GetPort(&tempPort);
  1158.                     if (wp->pwin != (WindowPtr) NULL) SetPort(wp->pwin);
  1159.                     switch (status = (*wp->taskp)(wp)) {
  1160.                         case NA_REQCLOSE:
  1161.                         case NA_CLOSED:
  1162.                             NAcloseWindow(wp, status);
  1163.                             break;
  1164.                     }
  1165.                     SetPort(tempPort);
  1166.                 }
  1167.                 if (!prioritycnt-- && (NActask = wp->task) != (na_win**) NULL) {
  1168.                     prioritycnt = (*NActask)->priority;
  1169.                 }
  1170.                 NAunlockWindowh(NActask, wp);
  1171.             }
  1172.             break;
  1173.     }
  1174.     if (status != NA_ALLCLOSED) goto MAINLOOP;
  1175.     
  1176.     while (NAtask != NULL) NAcloseWindow(NAlockWindow(NAtask), NA_REQCLOSE);
  1177.     
  1178.     DisposeRgn(NAfullRgn);
  1179.     DisposeRgn(NAnullRgn);
  1180. }
  1181.  
  1182. /* position a rectangle based on screen size
  1183.  */ 
  1184. #ifdef __STDC__
  1185. Rect *NAscreenrect(short position)
  1186. #else
  1187. Rect *NAscreenrect(position)
  1188.     short position;
  1189. #endif
  1190. {
  1191.     static short    stacktimes = 0;
  1192.     static Rect        sb;
  1193.     short topoffset, leftoffset;
  1194.             
  1195.     /* calculate the position to open the window */
  1196.     {
  1197.         int        four = 4;
  1198.         
  1199.         sb = QD(screenBits.bounds);
  1200.         InsetRect(&sb, four, four);
  1201.         sb.top += MBarHeight;
  1202.     }
  1203.     if (position & NA_TITLEOFFSET) {
  1204.         sb.top += 18;
  1205.     }
  1206.     {
  1207.         short     width, height;
  1208.         
  1209.         width = sb.right - sb.left;
  1210.         height = sb.bottom - sb.top;
  1211.         if (position & 0x03) {
  1212.             width = (width * (position & 0x03)) >> 2;
  1213.         }
  1214.         if (position & 0x0c) {
  1215.             height = (height * ((position & 0x0c) >> 2)) >> 2;
  1216.         }
  1217.         if (position & NA_TOPSCN) {
  1218.             sb.bottom = sb.top + height;
  1219.         } else if (position & NA_BOTTOMSCN) {
  1220.             sb.top = sb.bottom - height;
  1221.         } else {
  1222.             short bw = (sb.bottom - sb.top - height) >> 1;
  1223.             sb.top += bw;
  1224.             sb.bottom -= bw;
  1225.         }
  1226.         if (position & NA_LEFTSCN) {
  1227.             sb.right = sb.left + width;
  1228.         } else if (position & NA_RIGHTSCN) {
  1229.             sb.left = sb.right - width;
  1230.         } else {
  1231.             short bw = (sb.right - sb.left - width) >> 1;
  1232.  
  1233.             sb.left += bw;
  1234.             sb.right -= bw;
  1235.         }
  1236.         if (position & NA_STACK) {
  1237.             if (stacktimes >= 5) {
  1238.                 stacktimes = 0;
  1239.             }
  1240.             topoffset = 22 * stacktimes;
  1241.             leftoffset = (4 - stacktimes) * 4;
  1242.             if (sb.top + topoffset < sb.bottom) sb.top += topoffset;
  1243.             if (sb.left + leftoffset < sb.right) sb.left += leftoffset;
  1244.             ++stacktimes;
  1245.         }
  1246.     }
  1247.     
  1248.     return (&sb);
  1249. }
  1250.  
  1251. /* create a new window/dialog/task structure
  1252.  */
  1253. #ifdef __STDC__
  1254. short NAwindow(Rect *rpos, long flags, char *title, short res, long *initdata,
  1255.     long datasize, na_initp initp)
  1256. #else
  1257. short NAwindow(rpos, flags, title, res, initdata, datasize, initp)
  1258.     Rect            *rpos;
  1259.     long    flags;
  1260.     char            *title;
  1261.     short            res;
  1262.     long            *initdata;
  1263.     long            datasize;
  1264.     na_initp        initp;
  1265. #endif
  1266. {
  1267.     GrafPtr            tmpPort;
  1268.     short            procID;
  1269.     short    status;
  1270.     Boolean            goAwayFlag, visible;
  1271.     na_win    **winh, *winp;
  1272.     WindowPtr        behind, prev;
  1273.     PCstr            wtitle[256];
  1274.     
  1275.     /* save previous window */
  1276.     prev = FrontWindow();
  1277.     
  1278.     /* set up flags for the NewWindow call */
  1279.     goAwayFlag = (flags & NA_CLOSEBOX);
  1280.     visible = (flags & NA_NOTVISIBLE) ? false : true;
  1281.     behind = (flags & NA_BEHIND && NAwin != (na_win*) NULL) ? NAwin->pwin : (WindowPtr) -1;
  1282.     
  1283.     /* decide on the correct procID */
  1284.     {
  1285.         short    proc = rDocProc;
  1286.             
  1287.         if ((flags & NA_ROUNDBORDER) != NA_ROUNDBORDER) {
  1288.             proc = plainDBox;
  1289.             if (flags & NA_SHADOWBORDER)    proc = altDBoxProc;
  1290.             if (flags & NA_DOUBLEBORDER)    proc = dBoxProc;
  1291.             if (flags & NA_TITLEBAR)        proc = documentProc;
  1292.             if (!(flags & NA_GROWBOX)
  1293.                 && proc == documentProc)    proc |= noGrowDocProc;
  1294.             if (flags & NA_ZOOMBOX)            proc |= zoomDocProc;
  1295.         }
  1296.         procID = proc;
  1297.     }
  1298.     
  1299.     /* get the window title to a pacsal string */
  1300.     if (title) CtoPCstrcpy(wtitle, title);
  1301.         
  1302.     /* allocate memory and copy the user data */
  1303.     if (!datasize) datasize = sizeof (na_win);
  1304.     winh = (na_win**) NewHandleClear((Size) datasize);
  1305.     if (winh == (na_win**) NULL) return (NA_NOTPROCESSED);
  1306.     MoveHHi((Handle) winh);
  1307.     HLock((Handle) winh);
  1308.     winp = *winh;
  1309.     if (initdata != NULL && flags & NA_COPYDATA) {
  1310.         char *newdata;
  1311.         char *dcopy = (char *) initdata;
  1312.         
  1313.         datasize -= sizeof (na_win);
  1314.         for (newdata = (char*) winp + sizeof (na_win); datasize > 0; datasize--) {
  1315.             *newdata = *dcopy++;
  1316.             newdata++;
  1317.         }
  1318.     }
  1319.     
  1320.     /* initialize winp parameters */
  1321.     winp->locks = 1;
  1322.     winp->delay = NAdelay;
  1323.     winp->flags = flags;
  1324.     winp->minw = 128;
  1325.     winp->minh = 64;
  1326.     winp->resid = res;
  1327.         
  1328.     /* install in window tree */
  1329.     if (flags & NA_CHILDWINDOW && NAwin != (na_win*) NULL) {
  1330.         winp->parent = (na_win**) RecoverHandle((Ptr)NAwin);
  1331.         winp->next = NAwin->child;
  1332.         NAwin->child = winh;
  1333.     } else {
  1334.         winp->next = NAhead;
  1335.         NAhead = winh;
  1336.     }
  1337.     
  1338.     /* install in task list */
  1339.     if (flags & NA_HASTASK) {
  1340.         winp->task = NAtask;
  1341.         NAtask = winh;
  1342.     }
  1343.     
  1344.     {
  1345.         WindowPtr    window;
  1346.         
  1347.         /* open the window appropriately */
  1348.         switch (flags & (NA_COLORWINDOW | NA_DIALOGWINDOW)) {
  1349.             case NA_DIALOGWINDOW:
  1350.             case (NA_DIALOGWINDOW | NA_COLORWINDOW):
  1351.                 if (flags & NA_USERESOURCE) {
  1352.                     window = (WindowPtr) GetNewDialog(res, (Ptr) NULL, behind);
  1353.                 } else {
  1354.                     Handle items;
  1355.                     
  1356.                     items = GetResource('DITL', res);
  1357.                     DetachResource(items);
  1358.                     if (flags & NA_COLORWINDOW) {
  1359.                         window = (WindowPtr) NewCDialog((Ptr) NULL, rpos, wtitle,
  1360.                             visible, procID, behind, goAwayFlag, (long) winh, items);
  1361.                     } else {
  1362.                         window = (WindowPtr) NewDialog((Ptr) NULL, rpos, wtitle,
  1363.                             visible, procID, behind, goAwayFlag, (long) winh, items);
  1364.                     }
  1365.                 }
  1366.                 break;
  1367.                 
  1368.             case NA_COLORWINDOW:
  1369.                 if (flags & NA_USERESOURCE) {
  1370.                     window = (WindowPtr) GetNewCWindow(res, (Ptr) NULL, behind);
  1371.                 } else {
  1372.                     window = (WindowPtr) NewCWindow((Ptr) NULL, rpos, wtitle,
  1373.                         visible, procID, behind, goAwayFlag, (long) winh);
  1374.                 }
  1375.                 break;
  1376.             
  1377.             default:
  1378.                 if (flags & NA_USERESOURCE) {
  1379.                     window = GetNewWindow(res, (Ptr) NULL, behind);
  1380.                 } else {
  1381.                     window = NewWindow((Ptr) NULL, rpos, wtitle, visible, procID,
  1382.                         behind, goAwayFlag, (long) winh);
  1383.                 }
  1384.                 break;
  1385.         }
  1386.         if (title && (flags & NA_USERESOURCE)) SetWTitle(window, wtitle);
  1387.         winp->pwin = window;
  1388.     
  1389.         /* activate the window */
  1390.         GetPort(&tmpPort);
  1391.         SetPort(window);
  1392.     
  1393.         /* additional options for windows from resources */
  1394.         if (flags & NA_USERESOURCE) {
  1395.             SetWRefCon(window, (long) winh);
  1396.             
  1397.             /* force the size */
  1398.             if (flags & NA_FORCESIZE) {
  1399.                 MoveWindow(window, rpos->left, rpos->top, false);
  1400.                 SizeWindow(window, rpos->right - rpos->left, rpos->bottom - rpos->top, false);
  1401.             }
  1402.         }
  1403.         {
  1404.             Rect wsize, sb;
  1405.                 
  1406.             /* get the screen bounds */
  1407.             {
  1408.                 short    four = 4;
  1409.                 
  1410.                 sb = QD(screenBits.bounds);
  1411.                 InsetRect(&sb, four, four);
  1412.             }
  1413.             
  1414.             /* recenter a window -- great for dialog boxes */    
  1415.             wsize = window->portRect;
  1416.             LocalToGlobal((Point *)&wsize.top);
  1417.             if (flags & NA_RECENTER) {
  1418.                 LocalToGlobal((Point *)&wsize.bottom);
  1419.                 wsize.top = sb.top + (((sb.bottom - sb.top) - (wsize.bottom - wsize.top)) >> 1);
  1420.                 wsize.left = sb.left + (((sb.right - sb.left) - (wsize.right - wsize.left)) >> 1);
  1421.                 MoveWindow(window, wsize.left, wsize.top, false);
  1422.             }
  1423.             
  1424.             /* make sure the window is on the screen */
  1425.             if (wsize.top > sb.bottom || wsize.left > sb.right) {
  1426.                 short coord = 60;
  1427.                 
  1428.                 MoveWindow(window, coord, coord, false);
  1429.             }
  1430.         }
  1431.         
  1432.         /* call the init procedure */
  1433.         if ((status = (*initp)(winp, initdata)) >= NA_NOTPROCESSED) {
  1434.         
  1435.             /* draw the window immediately for better look & update has first newsize */
  1436.             if (winp->updatep == (na_updatep) NULL
  1437.                     || (status = (*winp->updatep)(winp, (Boolean) true))
  1438.                     == NA_NOTPROCESSED) {
  1439.                 DoDraw(winp, FrontWindow() != window ? DO_RESIZE | DO_DEACTIVATE :
  1440.                     DO_RESIZE);
  1441.             }
  1442.             if (flags & NA_DIALOGUPDATE) DrawDialog(window);
  1443.             ValidRect(&window->portRect);
  1444.         }
  1445.     
  1446.         /* deal with close requests/events result codes */
  1447.         switch (status) {
  1448.             case NA_ALLCLOSED:
  1449.             case NA_REQCLOSEALL:
  1450.                 status = NAcloseWindows(NAhead, status);
  1451.                 break;
  1452.     
  1453.             case NA_CLOSED:
  1454.             case NA_REQCLOSE:
  1455.                 status = NAcloseWindow(winp, status);
  1456.                 break;
  1457.             
  1458.             default:
  1459.                 NAunlockWindowh(winh, winp);
  1460.                 break;
  1461.         }
  1462.         
  1463.         /* give a nice return value & clean up the port */
  1464.         if (status == NA_NOTPROCESSED)                            status = NA_PROCESSED;
  1465.         if (FrontWindow() != window || status != NA_PROCESSED)    SetPort(tmpPort);
  1466.     }
  1467.     
  1468.     return (status);
  1469. }
  1470.  
  1471. /* add a new task to the task list, calling init procedure with data pointer
  1472.  */
  1473. void NAaddtask(taskp, size)
  1474.     na_taskp taskp;
  1475.     long size;
  1476. {
  1477.     na_win **task, *winp;
  1478.     
  1479.     if (!size) size = sizeof (na_win);
  1480.     task = (na_win **) NewHandleClear(size);
  1481.     (*task)->taskp = taskp;
  1482.     (*task)->task = NAtask;
  1483.     NAtask = task;
  1484. }
  1485.